﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.UI;
using YArchitech.LIB;
using HYRevitCode.ElementSearchUtility.LinkDocumentSuite;
using YJKRGeometry;
using Transfer.Utils;

namespace HYOpeningDetail
{
	internal class PublicFunction
	{
		private PublicFunction(ExternalCommandData commandData)
		{
			this.m_revit = commandData;
			this.m_uiDoc = this.m_revit.Application.ActiveUIDocument;
			this.m_doc = this.m_uiDoc.Document;
		}

		public static bool GetElementInfoBaseZ(ElementInfo input, out double baseZ)
		{
			baseZ = 0.0;
			BoundingBoxXYZ boundingBoxXYZ = input.element.get_BoundingBox(null);
			if (boundingBoxXYZ == null)
			{
				return false;
			}
			baseZ = boundingBoxXYZ.Min.Z;
			if (input.revitLink != null)
			{
				baseZ += LinkDocumentUtility.CalculateTransformEffectOnZ(input.revitLink.GetTotalTransform());
			}
			return true;
		}

		public static bool GetElementBaseZToNearLevel(ElementInfo input, out double findValue)
		{
			findValue = 0.0;
			double num;
			if (!PublicFunction.GetElementInfoBaseZ(input, out num))
			{
				return false;
			}
			Document document = input.element.Document;
			if (input.revitLink != null)
			{
				document = input.revitLink.Document;
			}
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(document).OfClass(typeof(Level));
			List<double> list = new List<double>();
			foreach (Element element in filteredElementCollector)
			{
				if (element != null && element is Level && YJKRGeometry.Geometry.LessThan((element as Level).Elevation, num))
				{
					list.Add((element as Level).Elevation);
				}
			}
			if (list.Count == 0)
			{
				findValue = num;
			}
			else
			{
				list = (from k in list
				orderby -k
				select k).ToList<double>();
				findValue = num - list[0];
			}
			return true;
		}

		public static void GetViewBox(ViewPlan viewPlan, List<double> m_lstLevelValue, ref BoundingBoxIntersectsFilter filterIntersect, bool bOffset)
		{
			double elevation = viewPlan.GenLevel.Elevation;
			double nearTopElevation = PublicFunction.GetNearTopElevation(elevation, m_lstLevelValue);
			BoundingBoxUV outline = viewPlan.Outline;
			UV uv = outline.Min * (double)viewPlan.Scale;
			UV uv2 = outline.Max * (double)viewPlan.Scale;
			double num = NumbericTools.mmToFeet(1.0);
			Outline outline2;
			if (bOffset)
			{
				outline2 = new Outline(new XYZ(uv.U, uv.V, elevation), new XYZ(uv2.U, uv2.V, nearTopElevation));
			}
			else
			{
				outline2 = new Outline(new XYZ(uv.U, uv.V, elevation + num), new XYZ(uv2.U, uv2.V, nearTopElevation - num));
			}
			filterIntersect = new BoundingBoxIntersectsFilter(outline2);
		}

		public static List<RevitLinkInstance> GetAllRevitLinkInstancesInDoc(Autodesk.Revit.DB.Document doc)
		{
			IEnumerable<ElementId> enumerable = new FilteredElementCollector(doc).OfClass(typeof(RevitLinkInstance)).ToElementIds();
			List<RevitLinkInstance> list = new List<RevitLinkInstance>();
			foreach (ElementId elementId in enumerable)
			{
				Element element = doc.GetElement(elementId);
				if (!(element.GetType() != typeof(RevitLinkInstance)))
				{
					RevitLinkInstance revitLinkInstance = element as RevitLinkInstance;
					if (revitLinkInstance != null)
					{
						list.Add(revitLinkInstance);
					}
				}
			}
			return list;
		}

		public static bool GetAllFace(Element equipIns, ref List<Face> lstFace, XYZ normal, Autodesk.Revit.DB.View view = null)
		{
			bool result;
			try
			{
				Options options = new Options();
				options.ComputeReferences = false;
				options.IncludeNonVisibleObjects = true;
				if (view != null)
				{
					options.View = view;
				}
				else
				{
					options.DetailLevel = (ViewDetailLevel)3;
				}
				foreach (GeometryObject geometryObject in equipIns.get_Geometry(options))
				{
					if (geometryObject is PlanarFace)
					{
						PlanarFace planarFace = geometryObject as PlanarFace;
						if (planarFace.FaceNormal.IsAlmostEqualTo(normal) || planarFace.FaceNormal.IsAlmostEqualTo(normal.Negate()))
						{
							lstFace.Add(geometryObject as PlanarFace);
						}
					}
					else if (geometryObject is Solid)
					{
						if (!PublicFunction.GetFaceBySolid(geometryObject as Solid, ref lstFace, normal))
						{
							return false;
						}
					}
					else if (geometryObject is GeometryInstance)
					{
						IEnumerator<GeometryObject> enumerator2 = (geometryObject as GeometryInstance).SymbolGeometry.GetEnumerator();
						{
							while (enumerator2.MoveNext())
							{
								if (!PublicFunction.GetFaceBySolid(enumerator2.Current as Solid, ref lstFace, normal))
								{
									return false;
								}
							}
						}
					}
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public static bool GetFaceBySolid(Solid solid, ref List<Face> lstFace, XYZ normal)
		{
			bool result;
			try
			{
				if (solid != null)
				{
					foreach (object obj in solid.Faces)
					{
						Face face = (Face)obj;
						if (face.GetType() == typeof(PlanarFace))
						{
							PlanarFace planarFace = face as PlanarFace;
							if (planarFace.FaceNormal.Normalize().IsAlmostEqualTo(normal) || planarFace.FaceNormal.Normalize().IsAlmostEqualTo(normal.Negate()))
							{
								lstFace.Add(face);
							}
						}
						else if (face.GetType() == typeof(CylindricalFace))
						{
							lstFace.Add(face);
						}
					}
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public static bool GetAllPoint(Transform transform, List<Face> lstFace, ref List<XYZ> lstPt)
		{
			bool result;
			try
			{
				foreach (Face face in lstFace)
				{
					foreach (XYZ xyz in face.Triangulate().Vertices)
					{
						XYZ item = transform.OfPoint(xyz);
						lstPt.Add(item);
					}
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public static bool GetMirrorPoint(List<XYZ> lstPt, ref List<XYZ> lstMirPt)
		{
			bool result;
			try
			{
				foreach (XYZ addPt in lstPt)
				{
					PublicFunction.AddPt2List(addPt, ref lstMirPt);
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		private static bool AddPt2List(XYZ addPt, ref List<XYZ> lstPt)
		{
			bool result;
			try
			{
				XYZ xyz = new XYZ(addPt.X, addPt.Y, 0.0);
				using (List<XYZ>.Enumerator enumerator = lstPt.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						if (enumerator.Current.IsAlmostEqualTo(xyz))
						{
							return true;
						}
					}
				}
				lstPt.Add(xyz);
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public static void GetGreater(double d1, double d2, ref double dMin, ref double dMax)
		{
			if (d1 - d2 <= 1E-06)
			{
				dMin = d1;
				dMax = d2;
				return;
			}
			dMin = d2;
			dMax = d1;
		}

		public static double GetNearTopElevation(double dCurElevation, List<double> m_lstLevelValue)
		{
			double num = 50.0;
			double item = m_lstLevelValue[m_lstLevelValue.Count - 1] + num;
			m_lstLevelValue.Add(item);
			for (int i = 0; i < m_lstLevelValue.Count - 1; i++)
			{
				double val = m_lstLevelValue[i];
				double num2 = m_lstLevelValue[i + 1];
				if (Transfer.Utils.Geometry.LessThan(dCurElevation, num2) && Transfer.Utils.Geometry.Greaterthan_Or_Equal(dCurElevation, val))
				{
					return num2;
				}
			}
			return dCurElevation + 3.0;
		}

		public static List<Level> GetSortLevels(Autodesk.Revit.DB.Document doc, double bottom, double top)
		{
			List<Level> list = new List<Level>();
			foreach (Element element in new FilteredElementCollector(doc).OfClass(typeof(Level)).ToElements())
			{
				Level level = element as Level;
				double elevation = level.Elevation;
				if (elevation >= bottom && elevation <= top)
				{
					list.Add(level);
				}
			}
			list.Sort(new LevelComparer());
			return list;
		}

		public static List<double> GetLevelValue(List<Level> lstAllLevels)
		{
			List<double> list = new List<double>();
			foreach (Level level in lstAllLevels)
			{
				double elevation = level.Elevation;
				list.Add(elevation);
			}
			return list;
		}

		public static double GetWallWidth(Wall wall)
		{
			return wall.WallType.get_Parameter(BuiltInParameter.WALL_ATTR_WIDTH_PARAM).AsDouble();
		}

		public static bool LineParallelFace(Line line, Face face)
		{
			XYZ xyz = line.Direction.Normalize();
			XYZ xyz2 = (face as PlanarFace).FaceNormal.Normalize();
			return Transfer.Utils.Geometry.IsEqual(xyz.AngleTo(xyz2), Math.PI*.5);
		}

		public static Line GetMEPCurveLine(Element elem)
		{
			LocationCurve locationCurve = elem.Location as LocationCurve;
			if (locationCurve == null)
			{
				return null;
			}
			return Line.CreateBound(locationCurve.Curve.GetEndPoint(0), locationCurve.Curve.GetEndPoint(1));
		}

		public static bool GetCvIntersect2ElemPoints(Curve cv, Element elem, ref Dictionary<XYZ, Element> dicPtIntersect)
		{
			bool result;
			try
			{
				XYZ endPoint = cv.GetEndPoint(0);
				XYZ endPoint2 = cv.GetEndPoint(1);
				XYZ zero = XYZ.Zero;
				XYZ zero2 = XYZ.Zero;
				if (PublicFunction.GetElemLocationCurve(elem, ref zero, ref zero2))
				{
					double z = zero.Z;
					XYZ xyz = new XYZ(endPoint.X, endPoint.Y, z);
					XYZ xyz2 = new XYZ(endPoint2.X, endPoint2.Y, z);
					Curve curve = Line.CreateBound(xyz, xyz2);
					IntersectionResultArray intersectionResultArray = null;
					Curve elemLocationCurve = PublicFunction.GetElemLocationCurve(elem);
                    if ((int)curve.Intersect(elemLocationCurve, out intersectionResultArray) == 8)
					{
						for (int i = 0; i < intersectionResultArray.Size; i++)
						{
							XYZ xyzpoint = intersectionResultArray.get_Item(i).XYZPoint;
							Curve curve2 = Line.CreateUnbound(xyzpoint, XYZ.BasisZ);
							IntersectionResultArray intersectionResultArray2 = null;
                            if ((int)curve2.Intersect(cv, out intersectionResultArray2) == 8 && intersectionResultArray2.Size > 0)
							{
								xyzpoint = intersectionResultArray2.get_Item(0).XYZPoint;
								if (!dicPtIntersect.Keys.Contains(xyzpoint))
								{
									dicPtIntersect.Add(xyzpoint, elem);
								}
							}
						}
					}
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			return result;
		}

		public static List<XYZ> GetCvIntersect2FloorPoints(Curve cv, Element elem, ref Dictionary<XYZ, Element> dicPtIntersectInfo)
		{
			List<XYZ> list = new List<XYZ>();
			try
			{
				if (elem is Floor)
				{
					Floor floor = elem as Floor;
					List<Face> list2 = new List<Face>();
					if (!PublicFunction.FindFloorFace(floor, ref list2, cv) || list2.Count == 0)
					{
						return null;
					}
					Line line = cv as Line;
					if (line == null)
					{
						return null;
					}
					using (List<Face>.Enumerator enumerator = list2.GetEnumerator())
					{
						while (enumerator.MoveNext())
						{
							if (!PublicFunction.LineIntersectPlaneFace(enumerator.Current, line, elem, ref dicPtIntersectInfo))
							{
								return null;
							}
						}
					}
					if (list.Count == 0)
					{
						return null;
					}
				}
			}
			catch (Exception)
			{
				return null;
			}
			return list;
		}

		private static bool FindFloorFace(Floor floor, ref List<Face> lstFace, Curve curve)
		{
			try
			{
				foreach (GeometryObject geometryObject in floor.get_Geometry(new Options
				{
					ComputeReferences = true,
                    DetailLevel = (ViewDetailLevel)3
				}))
				{
					if (geometryObject is Solid)
					{
						foreach (object obj in (geometryObject as Solid).Faces)
						{
							Face face = (Face)obj;
							IntersectionResultArray intersectionResultArray = null;
                            if ((int)face.Intersect(curve, out intersectionResultArray) == 8)
							{
								UV uvpoint = intersectionResultArray.get_Item(0).UVPoint;
								XYZ xyz = face.ComputeNormal(uvpoint);
								if (Transfer.Utils.Geometry.LessThan(XYZ.BasisZ.AngleTo(xyz.Normalize()), Math.PI*.5))
								{
									lstFace.Add(face);
								}
							}
						}
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private static bool LineIntersectPlaneFace(Face face, Line line, Element elem, ref Dictionary<XYZ, Element> dicPtIntersectInfo)
		{
			try
			{
				IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
				SetComparisonResult setComparisonResult = face.Intersect(line, out intersectionResultArray);
				if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
				{
					for (int i = 0; i < intersectionResultArray.Size; i++)
					{
						XYZ xyzpoint = intersectionResultArray.get_Item(i).XYZPoint;
						if (!dicPtIntersectInfo.Keys.Contains(xyzpoint))
						{
							dicPtIntersectInfo.Add(xyzpoint, elem);
						}
					}
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private static bool GetElemLocationCurve(Element elem, ref XYZ ptStart, ref XYZ ptEnd)
		{
			if (elem == null)
			{
				return false;
			}
			Curve elemLocationCurve = PublicFunction.GetElemLocationCurve(elem);
			if (elemLocationCurve != null)
			{
				ptStart = elemLocationCurve.GetEndPoint(0);
				ptEnd = elemLocationCurve.GetEndPoint(1);
				return true;
			}
			return false;
		}

		public static Curve GetElemLocationCurve(Element elem)
		{
			if (elem == null)
			{
				return null;
			}
			LocationCurve locationCurve = elem.Location as LocationCurve;
			if (locationCurve != null)
			{
				return locationCurve.Curve;
			}
			return null;
		}

		public static List<Curve> GetCurveProjectPoint(List<Curve> lstCurve, XYZ pt)
		{
			List<Curve> list = new List<Curve>();
			foreach (Curve curve in lstCurve)
			{
				XYZ xyz = new XYZ(curve.GetEndPoint(0).X, curve.GetEndPoint(0).Y, pt.Z);
				XYZ xyz2 = new XYZ(curve.GetEndPoint(1).X, curve.GetEndPoint(1).Y, pt.Z);
				Line item = Line.CreateBound(xyz, xyz2);
				list.Add(item);
			}
			return list;
		}

		public static bool IsRectangularDuct(Element elem)
		{
			foreach (object obj in (elem as Duct).ConnectorManager.Connectors)
			{
				Connector connector = (Connector)obj;
                if ((int)connector.ConnectorType == 1 && (int)connector.Shape == 1)
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsRectangularWaterCollection(string strKeyValue)
		{
			return strKeyValue.Contains("方");
		}

		public static bool IsRectangularWaterCollection(FamilyInstance famInstance)
		{
			List<Face> list = new List<Face>();
			PublicFunction.GetAllFace(famInstance, ref list, XYZ.BasisZ, null);
			if (list.Count < 1)
			{
				return false;
			}
			list = (from face in list
			orderby face.Area descending
			select face).ToList<Face>();
			foreach (object obj in list[0].EdgeLoops)
			{
				foreach (object obj2 in ((EdgeArray)obj))
				{
					Curve curve = ((Edge)obj2).AsCurve();
					if (!(curve == null) && curve is Arc)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static List<T> GetAllIntersectSubject<T>(Element mepElem, Autodesk.Revit.DB.Document doc, BuiltInCategory builtIncategory) where T : Element
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc);
			filteredElementCollector.OfCategory(builtIncategory).WhereElementIsNotElementType();
			ElementIntersectsElementFilter elementIntersectsElementFilter = new ElementIntersectsElementFilter(mepElem);
			filteredElementCollector.WherePasses(elementIntersectsElementFilter);
			List<T> list = new List<T>();
			foreach (Element element in filteredElementCollector)
			{
				if (element is T)
				{
					list.Add(element as T);
				}
			}
			return list;
		}

		public static Curve CreateOffsetCurve(Curve curve, XYZ vector, double dOffset)
		{
			XYZ xyz = curve.GetEndPoint(0).Add(vector * 0.5 * dOffset);
			XYZ xyz2 = curve.GetEndPoint(1).Add(vector * 0.5 * dOffset);
			return Line.CreateBound(xyz, xyz2);
		}

		public static TextNoteType GetTextType(string strTextNodeType, Autodesk.Revit.DB.Document doc)
		{
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(doc);
			filteredElementCollector.OfClass(typeof(TextNoteType));
			TextNoteType result = null;
			foreach (Element element in filteredElementCollector)
			{
				TextNoteType textNoteType = (TextNoteType)element;
				if (textNoteType.Name == strTextNodeType)
				{
					result = textNoteType;
					break;
				}
			}
			return result;
		}

		public static double GetElementLevel(ElementInfo eleInfo)
		{
			XYZ xyz;
			if (eleInfo.revitLink != null)
			{
				xyz = (eleInfo.element.Location as LocationPoint).Point;
				xyz = eleInfo.revitLink.GetTransform().OfPoint(xyz);
			}
			else
			{
				xyz = (eleInfo.element.Location as LocationPoint).Point;
			}
			return xyz.Z;
		}

		private ExternalCommandData m_revit;

		private UIDocument m_uiDoc;

		private Document m_doc;
	}
}
